package com.loveprogrammer.eternity.skill.support.skills;

import com.loveprogrammer.eternity.action.BaseAction;
import com.loveprogrammer.eternity.enums.*;
import com.loveprogrammer.eternity.model.Character;
import com.loveprogrammer.eternity.common.Tuple;
import com.loveprogrammer.eternity.model.attack.AttackEntity;
import com.loveprogrammer.eternity.model.attack.AttackResult;
import com.loveprogrammer.eternity.model.product.Equipment;
import com.loveprogrammer.eternity.model.product.equipment.Equips;
import com.loveprogrammer.eternity.notify.Notify;
import com.loveprogrammer.eternity.skill.Skill;
import com.loveprogrammer.eternity.skill.support.states.AbstractState;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @version 1.0.0
 * @description:
 * @author: eric
 * @date: 2022-08-11 17:31
 **/
public abstract class AbstractSkill extends BaseAction implements Skill, Serializable {

    private final int baseInterval;

    private int restInterval;

    private int level;

    private int id;

    private int order;

    private int maxLevel;

    private String name;

    private String desc;

    private ScheduledExecutorService subFightExecutorService;

    // 品质 初始是E
    private SkillQualityEnum quality = SkillQualityEnum.E;

    // 技能威力相关的三个数值，提取到抽象方法中统一管理
    private int baseHarm;

    private double percent = 0.35;

    private double ratio = 1.5;

    private boolean dodged;

    protected AbstractSkill(int id,int baseInterval,int level,int order,
                            int maxLevel,String name,String desc) {
        // 冷却时间
        this.baseInterval = baseInterval;
        this.restInterval = baseInterval;
        this.level = level;
        this.id = id;
        this.order = order;
        this.maxLevel = maxLevel;
        this.name = name;
        this.desc = desc;
        this.dodged = false;
    }

    protected AbstractSkill(int id,int baseInterval,int level,int order,
                            int maxLevel,String name,String desc,boolean dodged) {
        // 冷却时间
        this.baseInterval = baseInterval;
        this.restInterval = baseInterval;
        this.level = level;
        this.id = id;
        this.order = order;
        this.maxLevel = maxLevel;
        this.name = name;
        this.desc = desc;
        this.dodged = dodged;
    }

    @Override
    public int restInterval() {
        return restInterval;
    }

    @Override
    public void reduceInterval() {
        // 最小是0
        restInterval = Math.max(0,restInterval -1);
    }

    /**
     * @Author eric
     * @Param [character 技能持有者, attack, defences, subFightExecutorService, notify]
     * @return com.loveprogrammer.eternity.common.Tuple<java.lang.String,java.util.List<com.loveprogrammer.eternity.model.Character>>
     **/
    @Override
    public Tuple<String, List<Character>> launch(Character character,
                                                 List<? extends Character> attack,
                                                 List<? extends Character> defences,
                                                 ScheduledExecutorService subFightExecutorService) {
        if (!check(character)) {
            return null;
        }
        if(this.subFightExecutorService == null) {
            this.subFightExecutorService = subFightExecutorService;
        }
        if(restInterval <= 0) {
            // 得有能进攻的目标
            if(defences != null && defences.size() > 0) {
                Tuple<String, List<Character>> tuple = skillLaunch(character, attack, defences);
                this.restInterval = this.baseInterval;
                return tuple;
            }
        }
        return null;
    }

    @Override
    public boolean levelUp(int characterLevel) {
        // 检查是否能够升级
        if(checkLevelUp(characterLevel)) {
            // ConsolePrint.publishMessage("技能【" + getName() + "] 升级 （" + this.level + "->" + (this.level + 1) + ")");
            // 如果符合要求
            this.level += 1;
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getId() {
        return id;
    }

    @Override
    public String getDesc() {
        return desc;
    }

    @Override
    public int maxLevel() {
        return maxLevel;
    }

    @Override
    public int order() {
        return order;
    }

    protected abstract Tuple<String, List<Character>> skillLaunch(Character character,
                                                                  List<? extends Character> attack,
                                                                  List<? extends Character> defences);

    protected abstract int computeHarm(Character character);

    protected abstract int computeSecondHarm(Character character);
    /***
     * 发动技能
     **/
    public Tuple<String, List<Character>> simpleSkillLaunch(Character character,
                                                            List<? extends Character> defences,
                                                            Integer defaultPower) {
        Tuple<String, List<Character>> tuple = new Tuple();
        // 按照血量排序，攻击血量最低的
        Character defence = findSingleAttacker(defences,true);

        StringBuilder builder = new StringBuilder();
        builder.append(character.getName()).append("(").append(character.getCurrentHp()).append("/")
                .append(character.getHpMax()).append(")").append(" 使用技能[")
                .append(getName()).append(" ").append(getLevel()).append("级】攻击了 ").append(defence.getName());
        AttackEntity power;
        if(character.getAttackType() == 0){
            if(defaultPower != null){
                power = new AttackEntity(defaultPower, AttackTypeEnum.NORMAL);
            }else {
                power = new AttackEntity((int) (character.getStrength() * ((100 + 20 + getLevel() * 1.1) / 100)  * quality.getRatio()), AttackTypeEnum.NORMAL);
            }
        }else{
            if(defaultPower != null){
                power = new AttackEntity(defaultPower, AttackTypeEnum.MAGIC);
            }else {
                power = new AttackEntity((int) (character.getMagic() * ((100 + 20 + getLevel() * 1.1) / 100) * quality.getRatio()), AttackTypeEnum.MAGIC);
            }
        }
        // 暴击检测 提升200%的伤害 几率 技巧 + 500 / 技巧 + 6000
        boolean crit = critCheck(character);
        if(crit) {
            power.setHarm(critPower(power.getHarm()));
        }
        AttackResult attackResult = defence.defence(power);
        computeHarm(builder,crit,defence,attackResult,character,null,defences);
        List<Character> value = new ArrayList<>();
        value.add(defence);
        tuple.setKey(builder.toString());
        tuple.setValue(value);
        return tuple;
    }

    public boolean checkWeaponType(Character character,WeaponTypeEnum weaponTypeEnum){
        Equips equips = character.getEquips();
        if(equips == null){
            return false;
        }
        Equipment weapon = character.getEquips().getWeapon();
        return weapon != null
                && weapon.getWeaponTypeEnum() != null
                && weapon.getWeaponTypeEnum().equals(weaponTypeEnum);
    }

    public int getBaseInterval() {
        return baseInterval;
    }

    public int getRestInterval() {
        return restInterval;
    }

    public void setRestInterval(int restInterval) {
        this.restInterval = restInterval;
    }

    public int getLevel() {
        if(level <= 0) {
            level = 1;
        }
        return level;
    }

    @Override
    public void setLevel(int level) {
        this.level = level;
    }



    @Override
    public void release(Character character,
                        List<? extends Character> attack,
                        List<? extends Character> defences) {

    }

    public void setId(int id) {
        this.id = id;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    public void setMaxLevel(int maxLevel) {
        this.maxLevel = maxLevel;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public int getOrder() {
        return order;
    }

    public int getMaxLevel() {
        return maxLevel;
    }

    public AbstractSkill(int baseInterval, int restInterval, int level, int id, int order, int maxLevel, String name, String desc) {
        this.baseInterval = baseInterval;
        this.restInterval = restInterval;
        this.level = level;
        this.id = id;
        this.order = order;
        this.maxLevel = maxLevel;
        this.name = name;
        this.desc = desc;
    }

    @Override
    public void computeLevelByCharacterLevel(int level) {
        int temp = 1;
        for (int i = 0; i < level; i++) {
            if(checkLevelUp(i)){
                setLevel(temp++);
            }
        }
    }

    @Override
    public Skill assembleAttackEntity(AttackResult attackResult) {
        return this;
    }


    @Override
    public Skill assemble(Map<String, Object> properties) {
        // 配置
        properties.forEach(
                (key,value) -> {
                    if(key.equals("percent")){
                        this.setPercent(Double.parseDouble(value.toString()));
                        return;
                    }
                    if(key.equals("ratio")){
                        this.setRatio(Double.parseDouble(value.toString()));
                        return;
                    }
                    if(key.equals("baseHarm")){
                        this.setBaseHarm(Integer.parseInt(value.toString()));
                    }
                }
        );
        return this;
    }

    @Override
    public String print() {
        return "名称 ：" + getName() + ",品质 ：" + getQuality().getCode() + ", 说明：" + getDesc();
    }

    public int getBaseHarm() {
        if(baseHarm == 0){
            return defaultHarm();
        }
        return baseHarm;
    }

    public void setBaseHarm(int baseHarm) {
        this.baseHarm = baseHarm;
    }

    public double getPercent() {
        return percent;
    }

    public void setPercent(double percent) {
        this.percent = percent;
    }

    public double getRatio() {
        return ratio;
    }

    public void setRatio(double ratio) {
        this.ratio = ratio;
    }

    @Override
    public int defaultHarm() {
        return 50;
    }

    @Override
    public boolean canBeDodged() {
        return dodged;
    }

    public SkillQualityEnum getQuality() {
        return quality;
    }

    public void setQuality(SkillQualityEnum quality) {
        this.quality = quality;
    }

    public int getHarm(Character character) {
        return (int) (computeHarm(character) * quality.getRatio());
    }

    public int getSecondHarm(Character character) {
        return (int) (computeSecondHarm(character) * quality.getRatio());
    }

    public double getSecondHarmDouble(Character character) {
        return computeSecondHarm(character) * quality.getRatio();
    }

    @Override
    public void levelUpInit(int level, int acquiredLevel) {
        for (int i = acquiredLevel; i <= level; i++) {
            levelUp(i);
        }
    }
}
